'use strict';
/** 
  * A simple but useful and efficient directive to toggle a class to an element.   
*/
app.factory('ToggleHelper', ['$rootScope',
function ($rootScope) {
    return {

        events: {
            toggle: "clip-two.toggle",
            toggleByClass: "clip-two.toggleByClass",
            togglerLinked: "clip-two.linked",
            toggleableToggled: "clip-two.toggled"
        },

        commands: {
            alternate: "toggle",
            activate: "on",
            deactivate: "off"
        },

        toggle: function (target, command) {
            if (command == null) {
                command = "toggle";
            }
            $rootScope.$emit(this.events.toggle, target, command);
        },

        toggleByClass: function (targetClass, command) {
            if (command == null) {
                command = "toggle";
            }
            $rootScope.$emit(this.events.toggleByClass, targetClass, command);
        },

        notifyToggleState: function (elem, attrs, toggleState) {
            $rootScope.$emit(this.events.toggleableToggled, attrs.id, toggleState, attrs.exclusionGroup);
        },

        toggleStateChanged: function (elem, attrs, toggleState) {
            this.updateElemClasses(elem, attrs, toggleState);
            this.notifyToggleState(elem, attrs, toggleState);
        },

        applyCommand: function (command, oldState) {
            switch (command) {
                case this.commands.activate:
                    return true;
                case this.commands.deactivate:
                    return false;
                case this.commands.alternate:
                    return !oldState;
            }
        },

        updateElemClasses: function (elem, attrs, active) {

            if (active) {
                if (attrs.activeClass) {
                    elem.addClass(attrs.activeClass);
                }
                if (attrs.inactiveClass) {
                    elem.removeClass(attrs.inactiveClass);
                }
                var parent = elem.parent();
                if (attrs.parentActiveClass) {
                    parent.addClass(attrs.parentActiveClass);
                }
                if (attrs.parentInactiveClass) {
                    parent.removeClass(attrs.parentInactiveClass);
                }
            } else {
                if (attrs.inactiveClass) {
                    elem.addClass(attrs.inactiveClass);
                }
                if (attrs.activeClass) {
                    elem.removeClass(attrs.activeClass);
                }
                var parent = elem.parent();
                if (attrs.parentInactiveClass) {
                    parent.addClass(attrs.parentInactiveClass);
                }
                if (attrs.parentActiveClass) {
                    parent.removeClass(attrs.parentActiveClass);
                }
            }
        }
    };
}]).run(["$rootScope", "ToggleHelper",
function ($rootScope, ToggleHelper) {

    $rootScope.toggle = function (target, command) {
        if (command == null) {
            command = "toggle";
        }
        ToggleHelper.toggle(target, command);
    };

    $rootScope.toggleByClass = function (targetClass, command) {
        if (command == null) {
            command = "toggle";
        }
        ToggleHelper.toggleByClass(targetClass, command);
    };
}]).directive('ctToggle', ["$rootScope", "ToggleHelper",
function ($rootScope, ToggleHelper) {
    return {
        restrict: "A",
        link: function (scope, elem, attrs) {
            var command = attrs.ctToggle || ToggleHelper.commands.alternate;
            var target = attrs.target;
            var targetClass = attrs.targetClass;
            var bubble = attrs.bubble === "true" || attrs.bubble === "1" || attrs.bubble === 1 || attrs.bubble === "" || attrs.bubble === "bubble";

            if ((!target) && attrs.href) {
                target = attrs.href.slice(1);
            }

            if (!(target || targetClass)) {
                throw "'target' or 'target-class' attribute required with 'ct-toggle'";
            }
            elem.on("click tap", function (e) {

                var angularElem = angular.element(e.target);
                if (!angularElem.hasClass("disabled")) {
                    if (target != null) {
                        ToggleHelper.toggle(target, command);
                    }
                    if (targetClass != null) {
                        ToggleHelper.toggleByClass(targetClass, command);
                    }
                    if (!bubble) {
                        e.preventDefault();
                        return false;
                    } else {
                        return true;
                    }
                }

            });
            var unbindUpdateElemClasses = $rootScope.$on(ToggleHelper.events.toggleableToggled, function (e, id, newState) {
                if (id === target) {
                    ToggleHelper.updateElemClasses(elem, attrs, newState);
                }
            });

            if (target != null) {
                $rootScope.$emit(ToggleHelper.events.togglerLinked, target);
            }

            scope.$on('$destroy', unbindUpdateElemClasses);
        }
    };
}]).directive('toggleable', ["$rootScope", "ToggleHelper",
function ($rootScope, ToggleHelper) {
    return {
        restrict: "A",
        link: function (scope, elem, attrs) {
            var toggleState = false;

            if (attrs["default"]) {
                switch (attrs["default"]) {
                    case "active":
                        toggleState = true;
                        break;
                    case "inactive":
                        toggleState = false;
                }
                ToggleHelper.toggleStateChanged(elem, attrs, toggleState);
            }

            var unbindToggle = $rootScope.$on(ToggleHelper.events.toggle, function (e, target, command) {
                var oldState;
                if (target === attrs.id) {
                    oldState = toggleState;
                    toggleState = ToggleHelper.applyCommand(command, oldState);
                    if (oldState !== toggleState) {
                        ToggleHelper.toggleStateChanged(elem, attrs, toggleState);
                    }
                }
            });

            var unbindToggleByClass = $rootScope.$on(ToggleHelper.events.toggleByClass, function (e, targetClass, command) {
                var oldState;
                if (elem.hasClass(targetClass)) {
                    oldState = toggleState;
                    toggleState = ToggleHelper.applyCommand(command, oldState);
                    if (oldState !== toggleState) {
                        ToggleHelper.toggleStateChanged(elem, attrs, toggleState);
                    }
                }
            });

            var unbindToggleableToggled = $rootScope.$on(ToggleHelper.events.toggleableToggled, function (e, target, newState, sameGroup) {
                if (newState && (attrs.id !== target) && (attrs.exclusionGroup === sameGroup) && (attrs.exclusionGroup != null)) {
                    toggleState = false;
                    ToggleHelper.toggleStateChanged(elem, attrs, toggleState);
                }
            });

            var unbindTogglerLinked = $rootScope.$on(ToggleHelper.events.togglerLinked, function (e, target) {
                if (attrs.id === target) {
                    ToggleHelper.notifyToggleState(elem, attrs, toggleState);
                }
            });

            scope.$on('$destroy', function () {
                unbindToggle();
                unbindToggleByClass();
                unbindToggleableToggled();
                unbindTogglerLinked();
            });
        }
    };
}]);